package com.enation.app.javashop.core.goods.service.impl;

import com.enation.app.javashop.core.client.goods.GoodsQuantityClient;
import com.enation.app.javashop.core.client.trade.OrderClient;
import com.enation.app.javashop.core.goods.model.enums.QuantityType;
import com.enation.app.javashop.core.goods.model.vo.GoodsQuantityVO;
import com.enation.app.javashop.core.goods.service.GoodsStockManager;
import com.enation.app.javashop.core.promotion.groupbuy.service.GroupbuyGoodsManager;
import com.enation.app.javashop.core.promotion.newcomer.service.NewcomerGoodsManager;
import com.enation.app.javashop.core.promotion.seckill.service.SeckillGoodsManager;
import com.enation.app.javashop.core.promotion.shetuan.service.ShetuanGoodsManager;
import com.enation.app.javashop.core.promotion.shetuan.service.ShetuanGoodsOperateManager;
import com.enation.app.javashop.core.promotion.tool.model.dto.PromotionDTO;
import com.enation.app.javashop.core.promotion.tool.model.enums.PromotionTypeEnum;
import com.enation.app.javashop.core.trade.cart.model.vo.CartPromotionVo;
import com.enation.app.javashop.core.trade.cart.model.vo.CartSkuVO;
import com.enation.app.javashop.core.trade.order.model.dto.OrderDTO;
import com.enation.app.javashop.core.trade.order.model.enums.OrderStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author JFeng
 * @date 2020/12/26 18:05
 */
@Service
public class GoodsStockManagerImpl implements GoodsStockManager {

    @Autowired
    private GoodsQuantityClient goodsQuantityClient;

    @Autowired
    private OrderClient orderClient;


    @Autowired
    private SeckillGoodsManager seckillApplyManager;

    @Autowired
    private NewcomerGoodsManager newcomerGoodsManager;

    @Autowired
    private GroupbuyGoodsManager groupbuyGoodsManager;

    @Autowired
    private ShetuanGoodsOperateManager shetuanGoodsOperateManager;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    /***
     * 回滚普通库存
     * @param order
     */
    @Override
    public void rollbackNormal(OrderDTO order) {
        List<CartSkuVO> skuList = order.getSkuList();

        //获取订单中的sku信息
        List<GoodsQuantityVO> goodsQuantityVOList = buildQuantityList(skuList);

        rollbackReduce(goodsQuantityVOList);

    }

    /**
     * 锁普通商品库存
     *
     * @param order
     * @return
     */
    @Override
    public boolean lockNormalStock(OrderDTO order) {

        //获取订单中的sku信息
        List<CartSkuVO> skuList = order.getSkuList();
        List<GoodsQuantityVO> goodsQuantityVOList = buildQuantityList(skuList);

        //扣减正常库存，注意：如果不成功，库存在脚本里已经回滚，程序不需要回滚
        boolean normalResult = goodsQuantityClient.updateSkuQuantity(goodsQuantityVOList);

        if (logger.isDebugEnabled()) {
            logger.debug("订单【" + order.getSn() + "】商品锁库存结果为：" + normalResult);
        }

        return normalResult;
    }


    /**
     * 根据购物车列表构建要扣减的库存列表
     *
     * @param skuList
     * @return
     */
    private List<GoodsQuantityVO> buildQuantityList(List<CartSkuVO> skuList) {

        List<GoodsQuantityVO> goodsQuantityVOList = new ArrayList<>();
        for (CartSkuVO sku : skuList) {
            logger.debug("cart num is " + sku.getPurchaseNum());
            GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
            goodsQuantity.setSkuId(sku.getSkuId());
            goodsQuantity.setGoodsId(sku.getGoodsId());

            //设置为负数，要减掉的
            goodsQuantity.setQuantity(0 - sku.getNum());

            //设置为要扣减可用库存
            goodsQuantity.setQuantityType(QuantityType.enable);
            goodsQuantityVOList.add(goodsQuantity);

        }

        return goodsQuantityVOList;
    }


    /**
     * 回滚优惠库存
     *
     * @param order
     */
    @Override
    public void rollbackPromotionStock(OrderDTO order) {

        //获取订单中的sku信息
        List<CartSkuVO> skuList = order.getSkuList();
        //新人购
        List<PromotionDTO> promotionDTONewcomerList = new ArrayList<>();
        //限时抢购
        List<PromotionDTO> promotionDTOSekillList = new ArrayList<>();
        //团购
        List<PromotionDTO> promotionDTOGroupBuyList = new ArrayList<>();
        //社区团购
        List<PromotionDTO> promotionDTOShetuanList = new ArrayList<>();

        buildPromotionList(skuList, promotionDTONewcomerList,promotionDTOSekillList, promotionDTOGroupBuyList,promotionDTOShetuanList);

        seckillApplyManager.rollbackStock(promotionDTOSekillList);
        newcomerGoodsManager.rollbackStock(promotionDTONewcomerList);
        groupbuyGoodsManager.rollbackStock(promotionDTOGroupBuyList, order.getSn());
        //shetuanGoodsOperateManager.rollbackStock(promotionDTOShetuanList);

    }


    /**
     * 构建促销活动列表
     *
     * @param skuList
     * @param callbackNewcomerList 要构建的新人购列表
     * @param callbackSekillList 要构建的秒杀列表
     * @param callbackGroupList  要构建的团购列表
     */
    private void buildPromotionList(List<CartSkuVO> skuList, List<PromotionDTO> callbackNewcomerList, List<PromotionDTO> callbackSekillList, List<PromotionDTO> callbackGroupList,List<PromotionDTO> callbackShetuanList) {

        for (CartSkuVO sku : skuList) {

            List<CartPromotionVo> singleList = sku.getSingleList();
            if (singleList != null && singleList.size() > 0) {
                for (CartPromotionVo promotionGoodsVO : singleList) {

                    //如果优惠库存充足才可以是新人购
                    if (sku.getPurchaseNum() > 0) {
                        //判断是否参加的新人购的活动
                        if (promotionGoodsVO.getPromotionType().equals(PromotionTypeEnum.NEWCOMER.name())) {
                            PromotionDTO promotionDTO = new PromotionDTO();
                            promotionDTO.setActId(promotionGoodsVO.getActivityId());
                            promotionDTO.setGoodsId(sku.getGoodsId());
                            promotionDTO.setProductId(sku.getSkuId());
                            promotionDTO.setNum(sku.getPurchaseNum());
                            callbackNewcomerList.add(promotionDTO);
                        }
                        //判断是否参加的限时抢购的活动
                        if (promotionGoodsVO.getPromotionType().equals(PromotionTypeEnum.SECKILL.name())) {
                            PromotionDTO promotionDTO = new PromotionDTO();
                            promotionDTO.setActId(promotionGoodsVO.getActivityId());
                            promotionDTO.setGoodsId(sku.getGoodsId());
                            promotionDTO.setProductId(sku.getSkuId());
                            promotionDTO.setNum(sku.getPurchaseNum());
                            callbackSekillList.add(promotionDTO);
                        }

                        if (promotionGoodsVO.getIsCheck() == 1 && promotionGoodsVO.getPromotionType().equals(PromotionTypeEnum.GROUPBUY.name())) {
                            PromotionDTO promotionDTO = new PromotionDTO();
                            promotionDTO.setActId(promotionGoodsVO.getActivityId());
                            promotionDTO.setGoodsId(sku.getGoodsId());
                            promotionDTO.setNum(sku.getPurchaseNum());
                            callbackGroupList.add(promotionDTO);
                        }

                        if (promotionGoodsVO.getIsCheck() == 1 && promotionGoodsVO.getPromotionType().equals(PromotionTypeEnum.SHETUAN.name())) {
                            PromotionDTO promotionDTO = new PromotionDTO();
                            promotionDTO.setActId(promotionGoodsVO.getActivityId());
                            promotionDTO.setGoodsId(sku.getGoodsId());
                            promotionDTO.setProductId(sku.getSkuId());
                            promotionDTO.setNum(sku.getPurchaseNum());
                            callbackShetuanList.add(promotionDTO);
                        }

                    }

                }
            }

        }
    }

    /**
     * 扣减优惠库存
     *
     * @param order
     * @return
     */
    @Override
    public boolean lockPromotionStock(OrderDTO order) {

        boolean lockResult = false;

        //获取订单中的sku信息
        List<CartSkuVO> skuList = order.getSkuList();
        //新人购
        List<PromotionDTO> promotionDTONewcomerList = new ArrayList<>();
        //限时抢购
        List<PromotionDTO> promotionDTOSekillList = new ArrayList<>();
        //团购
        List<PromotionDTO> promotionDTOGroupBuyList = new ArrayList<>();
        //社区团购
        List<PromotionDTO> promotionDTOShetuanList = new ArrayList<>();

        buildPromotionList(skuList,promotionDTONewcomerList, promotionDTOSekillList, promotionDTOGroupBuyList,promotionDTOShetuanList);


        //扣减限时抢购库存
        boolean sekillResult = true;
        if (promotionDTOSekillList.size() > 0) {
            sekillResult = this.seckillApplyManager.addSoldNum(promotionDTOSekillList);
            if (logger.isDebugEnabled()) {
                logger.debug("秒杀锁库存结果为：" + sekillResult);
            }
        }

        //扣减新人购库存
        boolean newcomerResult = true;
        if (promotionDTONewcomerList.size() > 0) {
            newcomerResult = this.newcomerGoodsManager.addSalesNum(promotionDTOSekillList);
            if (logger.isDebugEnabled()) {
                logger.debug("秒杀锁库存结果为：" + sekillResult);
            }
        }

        //扣减团购库存
        boolean groupBuyResult = true;
        if (promotionDTOGroupBuyList.size() > 0) {
            groupBuyResult = this.groupbuyGoodsManager.cutQuantity(order.getSn(), promotionDTOGroupBuyList);
        }

        //扣减社区团购库存
        boolean shetuanResult = true;
        if (promotionDTOShetuanList.size() > 0) {
            //shetuanResult = this.shetuanGoodsOperateManager.cutQuantity(order.getSn(), promotionDTOShetuanList);
        }

        if (sekillResult && groupBuyResult && shetuanResult) {
            lockResult = true;
        }
        // 新人购
        if (newcomerResult && groupBuyResult && shetuanResult) {
            lockResult = true;
        }

        return lockResult;

    }


    private void rollbackReduce(List<GoodsQuantityVO> goodsQuantityVOList) {
        goodsQuantityVOList.forEach(goodsQuantityVO -> {
            goodsQuantityVO.setQuantity(0 - goodsQuantityVO.getQuantity());
        });
        goodsQuantityClient.updateSkuQuantity(goodsQuantityVOList);
    }

    /**
     * 修改订单状态
     *
     * @param sn    订单sn
     * @param times 次数
     * @return 是否修改成功
     */
    @Override
    public boolean updateState(String sn, Integer times, OrderStatusEnum status) {
        try {
            // 失败三次后直接返回
            if (times >= 3) {
                logger.error("订单状态重试三次后更新失败,订单号为" + sn + ",重试");
                return false;
            }
            // 更改订单状态为已确认
            boolean result = orderClient.updateOrderStatus(sn, status);

            if (logger.isDebugEnabled()) {
                logger.debug("更新订单【" + sn + "】状态为[" + status + "]第[" + times + "次]结果：" + result);
            }
            if (!result) {
                // 如果更新失败，则等待1秒重试
                Thread.sleep(1000);
                return updateState(sn, ++times, status);
            } else {
                return true;
            }
        } catch (Exception e) {
            logger.error("订单状态更新失败,订单号为" + sn + ",重试" + ++times + "次,消息" + e.getMessage());
            updateState(sn, ++times, status);
        }
        return true;
    }

    /**
     * 修改订单状态
     *
     * @param sn          订单sn
     * @param times       次数
     * @param orderStatus 订单状态
     * @return 是否修改成功
     */
    @Override
    public boolean updateTradeState(String sn, Integer times, OrderStatusEnum orderStatus) {
        try {
            // 失败三次后直接返回
            if (times >= 3) {
                logger.error("交易状态重试三次后更新失败,交易号为" + sn + ",重试");
                return false;
            }
            // 更改交易状态为已确认
            if (!orderClient.updateTradeStatus(sn, orderStatus)) {
                // 如果更新失败，则等待1秒重试
                Thread.sleep(1000);
                return updateTradeState(sn, ++times, orderStatus);
            } else {
                return true;
            }
        } catch (Exception e) {
            logger.error("交易状态更新失败,订单号为" + sn + ",重试" + ++times + "次,消息" + e.getMessage());
            updateState(sn, ++times, orderStatus);
        }
        return false;
    }
}
